home *** CD-ROM | disk | FTP | other *** search
- /*
- C* -- Parser Part I (statements)
-
- source: par.c
- started: October 22, 1985
- version:
- March 5, 1987
- March 7, 1989
-
- PUBLIC DOMAIN SOFTWARE
-
- The CSTAR program was placed in the public domain on June 15, 1991,
- by its author and sole owner,
-
- Edward K. Ream
- 1617 Monroe Street
- Madison, WI 53711
- (608) 257-0802
-
- CSTAR may be used for any commercial or non-commercial purpose.
-
- See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
- */
- #include "cstar.h"
-
- /*
- Externally visible routines defined in this module:
- */
- void mark_noneed (struct node *p);
- void need (int token);
- bool needend (int token);
- void pn_init (void);
- void program (void);
-
- /*
- Internal routines:
- */
- static struct lab_node * gl_enter (char * symbol);
- static void gl_init (void);
- static struct lab_node * gl_lookup (char * symbol);
- static void ll_check (void);
- static struct lab_node * ll_enter (char * symbol);
- static void ll_init (void);
- static struct lab_node * ll_lookup (char * symbol);
-
- static void pn_append (register struct node *p,
- struct node **last, struct node **head);
-
- static struct node * pn_break (void);
- static struct fbody * pn_body (char * name);
- static struct node * pn_case (void);
- static struct node * pn_continue (void);
- static struct node * pn_default (void);
- static struct node * pn_do (void);
- static void pn_err_need (char * s);
- static struct node * pn_for (void);
- static struct node * pn_goto (void);
- static void pn_head (void);
- static struct node * pn_if (void);
- static struct node * pn_label (void);
- static struct node * pn_list (bool one_flag);
- static struct node * pn_return (void);
- static struct node * pn_switch (void);
- static struct node * pn_while (void);
- static struct node * pn_x (void);
- static struct node * pn_x1 (int subtype);
- static struct node * pn_xlab (void);
- static struct node * pn_z (void);
- static struct node * pn_z1 (int subtype);
-
- /*
- externals variables.
- */
- extern struct st_node * intrn_decl;
-
- /*
- D A T A S T R U C T U R E S.
- */
-
- /*
- The brk_ref, cont_ref, sw_ref are back pointers to the parent
- nodes for break, continue and default statements.
- Initialized by program().
- */
- static struct node * brk_ref; /* Current break reference. */
- static struct node * cont_ref; /* Current continue reference. */
- static struct node * sw_ref; /* Current switch reference. */
-
- /*
- Define format of a label list node.
- The spelling of the symbol is in lab_label -> c_labsym.
-
- WARNING: not yet and maybe never.
- There are two user label tables--one local and one global.
- Global labels are an extension to the C language and preclude
- any occurence of a local label with the same spelling.
- */
- static struct lab_node {
- struct lab_node * lab_next;
- bool lab_defined; /* Defined flag. */
- struct node * lab_label; /* culabel_node. */
- };
- static struct lab_node ll_head; /* Header for local label list. */
- static struct lab_node gl_head; /* Header for global label list. */
-
- struct lab_node * ll_enter(), * ll_lookup();
- struct lab_node * gl_enter(), * gl_lookup();
-
- /*
- E X T E R N A L L Y V I S I B L E R O U T I N E S.
- */
-
- /*
- mark an outer statement or the product of an alist run as OPT_NONEED
- this is also called by setype2 to mark arg1 of a comma
-
- the mark indicates that the actual result of the item will never
- be used, so that, for example, x++ need not store the pre-value
- of x in a temporary.
- */
- void
- mark_noneed(struct node *p)
- {
- TRACEPB("mark_noneed", printf("(%p)\n", p));
-
- if (is_argop(p -> n_type)) {
- p -> n_oflags |= OPT_NONEED;
- }
- else if (p -> n_type == SEPARATOR_TOK) {
- mark_noneed(p -> n_car);
- mark_noneed(p -> n_next);
- }
-
- TICKX("mark_noneed");
- }
-
- /*
- Skip the current token if it is what we think it is.
- */
- void
- need(int token)
- {
- TRACEP("need", printf("(%d = %s)\n", token, ps_tok(token)));
-
- if (t_type == token) {
- get_token();
- return;
- }
- else {
- if (token) {
- pn_err_need(ps_tok(token));
- }
- else {
- pn_err_need("primitive");
- }
- return;
- }
- }
-
- /*
- error message about needed symbol
- */
- static void
- pn_err_need(char *s)
- {
- SL_DISABLE();
-
- switch(t_type) {
- case ID_TOK:
- t_3serr(NULL, s, " expected at: ", t_symbol);
- break;
- case Z_TOK:
- case X_TOK:
- t_3serr(NULL, s, " expected at keyword: ", t_symbol);
- break;
- default:
- if (ps_tok(t_type)) {
- t_3serr(NULL, s, " expected at: ", ps_tok(t_type));
- }
- else {
- t_2error(s, " expected");
- }
- }
- }
-
- /*
- If the current token is tok, return TRUE and eat it.
-
- Otherwise find the next instance of tok, eat it, and
- return false
- -- BUT --
- stop on and return an intervening semicolon or brace.
- */
- bool
- needend(int tok)
- {
- TRACEP("needend", printf("(%d = %s)\n", tok, ps_tok(tok)));
-
- if (t_type == tok) {
- get_token();
- return TRUE;
- }
-
- pn_err_need(ps_tok(tok));
-
- for(;;) {
- switch(t_type) {
- case SEMICOLON_TOK:
- case LCURLY_TOK:
- case RCURLY_TOK:
- case EOF_TOK:
- case EOP_TOK:
- return FALSE;
- }
- get_token();
- if (t_type == tok) {
- get_token();
- return FALSE;
- }
- }
- }
-
- /*
- Set up constants and so on.
- */
- void
- pn_init(void)
- {
- TICKB("pn_init");
-
- scope.s_scope = FILE_SCOPE;
- scope.s_snext = NULL;
- scope.s_fntype = NULL;
-
- /* Initialize the label tables. */
- gl_init();
- ll_init();
-
- TICKX("pn_init");
- }
-
-
-
- /*
- This is the main routine of the parser.
- It looks for external declarations and function definitions.
- Anything else is ignored with a warning message.
- */
- void
- program(void)
- {
- register struct st_node * id;
-
- /* Initialize chains of references. */
-
- TICKB("program");
-
- brk_ref = NULL;
- cont_ref = NULL;
- sw_ref = NULL;
-
- /* Put signature into file */
- if (!nogen_flag) {
- syssput("* ----- C Star compilation");
- sysnlput();
- }
-
- /* Get the first token of the program. */
- get_token();
-
- for (;;) {
- switch(t_type) {
-
- case EOP_TOK:
- case EOF_TOK:
- RETURN_VOID("program");
-
- case X_TOK:
- (void) pn_x();
- break;
-
- case Z_TOK:
- (void) pn_z();
- break;
-
- case ID_TOK:
-
- /* Do character-oriented lookahead. */
- skip_bl();
- if (ch == ':') {
- /* External label--extension to C. */
- pn_label();
- break;
- }
- /* must be decl or function definition or error */
- pn_head();
- break;
-
- case RCURLY_TOK:
- t_warning("check program structure");
- fatal("one } too many");
-
- case LCURLY_TOK:
- t_warning("check program structure");
- fatal("{ in outer context");
-
- default:
- if (is_kdecl(t_type)) {
- pn_head();
- }
- else {
- t_error("declaration or pseudo-op expected in outer context");
- fatal("program structure too confusing");
- }
- break;
-
- } /* End switch */
- } /* End for */
- }
-
- /*
- I N T E R N A L R O U T I N E S.
- */
-
- /*
- Append list p to list whose last element and first element are given.
- Update *last and *head.
- */
- static void
- pn_append(register struct node *p, struct node **last, struct node **head)
- {
- TRACEPB("pn_append", printf("(%p, %p, %p)\n", p, last, head));
-
- if (p == NULL) {
- RETURN_VOID("pn_append");
- }
-
- /* enter p on the list */
- if (*head == NULL) {
- *head = p;
- }
- else {
- (*last) -> n_next = p;
- }
-
- while (p -> n_next != NULL) {
- p = p -> n_next;
- }
-
- *last = p;
-
- TRACEPX("pn_append",
- printf("returns: %p->%p, *last %p, *head %p\n",
- p, p -> n_cltype, *last, *head));
- }
-
- /*
- Parse a declaration, which may lead into a function body.
-
- This routine calls code().
-
- This routine releases the local symbol table; code() does
- not do that any longer.
- */
- static void
- pn_head(void)
- {
- unsigned long f_size;
- struct fbody * fn_body;
- register struct type_node *t, *tf;
- register struct node *p;
- register struct st_node *id;
- struct type_node *head_x;
-
- TICKB("pn_head");
-
- scope.s_scope = FILE_SCOPE;
-
- /* fndef sees that there were explicit parentheses in some tail */
- /* head_x only makes sense for singular call ... */
- t = pd_stmt(DELEMENT_TYPE, FALSE, &head_x);
-
- if (t && (is_kdecl(t_type) || t_type == LCURLY_TOK)) {
-
- TRACE("pn_head",
- printf("pn_head: apparent function definition: type=%p\n",t));
-
- if (!pd_is1func(t)) {
- t_error("declaration leads into a function definition");
- fatal("program structure too confusing");
- }
- if (head_x -> t_typtok == FUNCTION_TYPE) {
- t_error("this way of defining a function is too cute");
- }
-
- if (id = t -> t_parent) {
- switch(id -> st_sclass) {
- case CODE_CLASS:
- case SCODE_CLASS:
- break;
- default:
- t_error("invalid storage class");
- id -> st_sclass = GLOBAL_CLASS;
- }
- }
- else {
- fatal("pn_head: internal: no parent");
- }
-
- tf = t -> t_link; /* function-returning node itself */
- /* t is the delement node */
- TRACEP("pn_head",
- printf("leads into function %s, type=%p\n",
- id -> st_name, tf));
-
- /* note: the formals are now attached to the function type */
-
- if(t_type != LCURLY_TOK) {
- /* then it's a k_decl */
- TRACE("pn_head", printf("formal declarations\n"));
- scope.s_scope = FNDEF_SCOPE;
- (void) pd_stmt(NULL_TYPE, TRUE, NULL);
- TRACE("pn_head", pr_type(tf);printf("\n"));
- }
-
- /* clear the local allocations */
- regs_clear();
- gen_init();
-
- /* size the formals and generate register moves */
- f_size = pd_alloc(tf -> t_list, 0);
-
- /* may want to make a node to hold the size */
- /* it does not belong in t_tsize */
- scope.s_scope = BLOCK_SCOPE;
- scope.s_fntype = tf;
-
- if (t_type != LCURLY_TOK) {
- t_error("{ expected in function definition");
- fatal("program structure too confusing");
- }
- else {
- /* Parse the body of the function. */
- fn_body = pn_body(id -> st_name);
- fn_body -> fname = id -> st_alias;
- fn_body -> formals = tf -> t_list;
- fn_body -> fml_size = f_size;
- fn_body -> ftype = tf;
- fn_body -> fclass = id -> st_sclass;
-
- /* Check for referenced but not defined labels. */
- ll_check();
-
- /* Generate code for the function !! */
- gen_function(fn_body);
- }
-
- /* clear the symbol table and release memory */
- pd_orphan(tf -> t_list);
- lst_init();
- ll_init();
- ml_release();
- scope.s_scope = FILE_SCOPE;
- scope.s_fntype = NULL;
- }
- else {
- if (t_type == SEMICOLON_TOK) {
- TRACE("decls",
- printf(">> Outer definition:\n");
- pr_type(t);
- printf("\n\n");
- );
-
- /* Generate code for outer definiitions. */
- out_decl(t);
- }
- need(SEMICOLON_TOK);
- }
-
- TICKX("pn_head");
- }
-
- /*
- Parse a function body. First declarations, then statements.
- This is called in whatever SCOPE it is called in.
- The body ends with the absorption of the terminal }.
-
- WARNING:
- If declarations are found after the initial declarations,
- t_error should be raised, and then they should be
- parsed by pd_stmt(NULL_TYPE, TRUE, NULL). Among other
- things, this will cause a fatal error and a warning to
- examine braces if one of the declarations looks like a
- function definition.
-
- scope.s_fntype is the function type-node encompassing the body
-
- WARNING: return expressions are not checked yet
- */
- static struct fbody *
- pn_body(char *name)
- {
- register struct st_node *id;
- static struct fbody b;
-
- TRACEPB("pn_body", printf("(%s)\n", name));
-
- call_1arg = 0;
-
- /*
- WARNING:
- If blocks are implemented, this will get more complicated.
- */
-
- if (t_type != LCURLY_TOK) {
- fatal("pn_body: internal: called without opening {");
- }
- get_token();
-
- /* Parse the initial local definitions. */
- if (t_type == ID_TOK) {
- if (id = ast_lookup(t_symbol)) {
- if (id -> st_sclass != TYPEDEF_CLASS) {
- id = NULL;
- }
- }
- }
- else {
- id = NULL;
- }
-
- if (is_kdecl(t_type) || id) {
- b . locals = pd_stmt(DELEMENT_TYPE, TRUE, NULL);
- b . lcl_size = pd_alloc(b . locals, 1);
- }
- else {
- b . locals = 0;
- b . lcl_size = 0;
- }
- intrn_decl = NULL;
-
- /* Parse the executable statements of the function body. */
- b . parse = pn_list(FALSE);
-
- need(RCURLY_TOK);
-
- RETURN_PTR("pn_body", &b);
- }
-
- /*
- Parse an expression inside required parentheses
- */
- static struct node *
- parenexp(void)
- {
- register struct node * p;
-
- TICKB("parenexp");
-
- need(LPAREN_TOK);
- p = pe_expr();
- (void) pe_check(p, XARITH_EXPR);
- (void) needend(RPAREN_TOK);
-
- RETURN_PTR("parenexp", p);
- }
-
-
- /*
- Parse a single statement--either one statement, terminated by ;
- or else a {} enclosed group.
-
- Typically this statement is the consequence of a conditional.
- In pl/68k, it must be a compound statement.
- */
- static struct node *
- pn_1stat(void)
- {
- register struct node *p;
-
- TICKB("pn_1stat");
-
- if (t_type == LCURLY_TOK) {
- get_token();
- p = pn_list(FALSE);
- need(RCURLY_TOK);
- RETURN_PTR("pn_1stat", p);
- }
- else {
- if (!full_c) {
- need(LCURLY_TOK);
- }
- RETURN_PTR("pn_1stat", pn_list(TRUE));
- }
- }
-
- /*
- Parse a single statement--either one statement, terminated by ;
- or else a {} enclosed group.
- */
- static struct node *
- pn_1astat(void)
- {
- register struct node *p;
-
- TICKB("pn_1astat");
-
- if (t_type == LCURLY_TOK) {
- get_token();
- p = pn_list(FALSE);
- need(RCURLY_TOK);
- RETURN_PTR("pn_1astat", p);
- }
- else {
- if (!full_c) {
- switch(t_type) {
- case K_FOR:
- case K_DO:
- case K_WHILE:
- case K_SWITCH:
- break;
- default:
- need(LCURLY_TOK);
- }
- }
- RETURN_PTR("pn_1astat", pn_list(TRUE));
- }
- }
-
- /*
- Parse a list of statements, not including '{' and '}'.
- This does NOT include a function argument list!!!
- */
- static struct node *
- pn_list(bool one_flag)
- {
- register struct node * p;
- struct node * head, * last;
- char *s;
-
- /* No statements have been seen yet. */
-
- TRACEPB("pn_list", printf("(%d)\n", one_flag));
-
- last = NULL;
- head = NULL;
- p = NULL;
- goto around;
-
- linkit:
- TRACEP("pn_list", printf("last: %p head: %p\n", last, head));
- pn_append(p, &last, &head);
- TRACEP("pn_list", printf("last: %p head: %p\n", last, head));
-
- next:
- if (one_flag) {
- RETURN_PTR("pn_list", head);
- }
-
- around:
- switch(t_type) {
-
- case EOF_TOK:
- case EOP_TOK:
- case RCURLY_TOK:
- RETURN_PTR("pn_list", head);
-
- case LCURLY_TOK:
- p = pn_1stat();
- goto linkit;
-
- case SEMICOLON_TOK:
- get_token();
- goto next;
-
- case K_BREAK: p = pn_break(); goto linkit;
- case K_CASE: p = pn_case(); goto linkit;
- case K_CONTINUE: p = pn_continue(); goto linkit;
- case K_DEFAULT: p = pn_default(); goto linkit;
- case K_DO: p = pn_do(); goto linkit;
- case K_FOR: p = pn_for(); goto linkit;
- case K_GOTO: p = pn_goto(); goto linkit;
- case K_IF: p = pn_if(); goto linkit;
- case K_RETURN: p = pn_return(); goto linkit;
- case K_SWITCH: p = pn_switch(); goto linkit;
- case K_WHILE: p = pn_while(); goto linkit;
-
- case X_TOK: p = pn_x(); goto linkit;
- case Z_TOK: p = pn_z(); goto linkit;
-
- case ID_TOK:
- /* Do character-oriented lookahead. */
- skip_bl();
- if (ch == ':') {
- p = pn_label();
- goto linkit;
- }
- goto expression;
-
- default:
- if (is_kdecl(t_type)) {
- fatal("declaration in code: check brace structure");
- }
- expression:
- TRACEP("pn_list", printf("presumed expression\n"));
- p = pe_expr();
- (void) pe_check(p, ASSIGN_EXPR);
- if (!needend(SEMICOLON_TOK)) {
- goto around;
- }
- mark_noneed(p);
- goto linkit;
- }
- }
-
- /*
- C O M P L E X S T A T E M E N T S.
- */
-
- /*
- Parse the "do" statement.
- */
- static struct node *
- pn_do(void)
- {
- register struct node * oldcont;
- register struct node * oldbrk;
- register struct node * p;
-
- /* Read the "do" */
-
- TICKB("pn_do");
-
- get_token();
-
- /* Allocate data structures. */
- p = new_pnode(sizeof(struct do_node));
- p -> n_type = K_DO;
-
- /* Update reference lists. */
- oldcont = cont_ref; cont_ref = p;
- oldbrk = brk_ref; brk_ref = p;
-
- /* Parse. */
- p -> n_dbdy = pn_1stat();
- need(K_WHILE);
- p -> n_dbool = parenexp();
-
- /* Restore reference lists. */
- cont_ref = oldcont;
- brk_ref = oldbrk;
-
- RETURN_PTR("pn_do", p);
- }
-
- /*
- Parse the "for" statement.
- */
- static struct node *
- pn_for(void)
- {
- register struct node * oldcont;
- register struct node * oldbrk;
- register struct node * p;
-
- /* Read the "for" */
-
- TICKB("pn_for");
-
- get_token();
-
- /* Allocate data structures. */
- p = new_pnode(sizeof(struct for_node));
- p -> n_type = K_FOR;
-
- /* Update reference lists. */
- oldcont = cont_ref; cont_ref = p;
- oldbrk = brk_ref; brk_ref = p;
-
- /* Parse. */
- need(LPAREN_TOK);
- mark_noneed(p -> n_f1list = pe_list(ASSIGN_EXPR));
-
- if (t_type == SEMICOLON_TOK) {
- get_token();
- p -> n_fbool = pe_expr();
- if (t_type == SEMICOLON_TOK) {
- get_token();
- mark_noneed(p -> n_f2list = pe_list(ASSIGN_EXPR));
- }
- else {
- t_error("missing ; in for");
- }
- }
- else {
- t_error("missing ; in for");
- }
-
- (void) needend(RPAREN_TOK);
- p -> n_fbdy = pn_1astat();
-
- /* Restore reference lists. */
- cont_ref = oldcont;
- brk_ref = oldbrk;
-
- RETURN_PTR("pn_for", p);
- }
-
- /*
- Parse the "if" statement.
- */
- static struct node *
- pn_if(void)
- {
- register struct node * p;
-
- /* Skip the "if" */
-
- TICKB("pn_if");
-
- get_token();
-
- /* Allocate data structures. */
- p = new_pnode(sizeof(struct if_node));
- p -> n_type = K_IF;
-
- /* Parse. */
- p -> n_ibool = parenexp();
- p -> n_ithen = pn_1astat();
- if (t_type == K_ELSE) {
- get_token();
- if (t_type == K_IF) {
- /* else if is like a new keyword. */
- p -> n_ielse = pn_list(TRUE);
- }
- else {
- p -> n_ielse = pn_1stat();
- }
- }
- else {
- p -> n_ielse = NULL;
- }
- RETURN_PTR("pn_if", p);
- }
-
- /*
- Parse the "switch" statement.
- */
- static struct node *
- pn_switch(void)
- {
- register struct node * oldswitch;
- register struct node * oldbrk;
- register struct node *p;
- register struct node *p1;
-
- /* Read the "switch" */
-
- TICKB("pn_switch");
-
- get_token();
-
- /* Allocate data structures. */
- p = new_pnode(sizeof(struct switch_node));
- p -> n_type = K_SWITCH;
-
- /* Update reference lists. */
- oldswitch = sw_ref; sw_ref = p;
- oldbrk = brk_ref; brk_ref = p;
-
- /* Parse expression and statement */
- p -> n_sval = p1 = parenexp();
- if (p1 && p1 -> n_cltype -> t_mclass & LONG_MOD) {
- t_error("switch variable is long");
- }
- switch(t_type) {
- case K_FOR:
- case K_WHILE:
- case K_DO:
- t_help("structure right after switch is never initialized");
- break;
- case K_CASE:
- case LCURLY_TOK:
- break;
- default:
- t_warning("code right after switch is unreachable");
- }
-
- /* if there's more structures before the body, fine */
- p -> n_sbdy = pn_1stat();
-
- sw_ref = oldswitch;
- brk_ref = oldbrk;
-
- RETURN_PTR("pn_switch", p);
- }
-
- /*
- Parse the "while" statement.
- */
- static struct node *
- pn_while(void)
- {
- register struct node * oldcont;
- register struct node * oldbrk;
- register struct node * p;
-
- /* Read the "while" */
-
- TICKB("pn_while");
-
- get_token();
-
- /* Allocate data structures. */
- p = new_pnode(sizeof(struct while_node));
- p -> n_type = K_WHILE;
-
- /* Update reference lists. */
- oldcont = cont_ref; cont_ref = p;
- oldbrk = brk_ref; brk_ref = p;
-
- /* Parse. */
- p -> n_wbool = parenexp();
- p -> n_wbdy = pn_1stat();
-
- /* Restore reference lists. */
- cont_ref = oldcont;
- brk_ref = oldbrk;
-
- RETURN_PTR("pn_while", p);
- }
-
- /*
- S U B O R D I N A T E S T A T E M E N T S.
- */
-
- /*
- Parse the "break" statement.
- */
- static struct node *
- pn_break(void)
- {
- register struct node * p;
-
- /* Read the "break" */
-
- TICKB("pn_break");
-
- get_token();
-
- /* Make sure the break appears in a switch, do, while or for. */
- if (brk_ref == NULL) {
- t_error("break does not match any statement");
- RETURN_PTR("pn_break", NULL);
- }
-
- /* Allocate a break/continue node. */
- p = new_pnode(sizeof(struct bc_node));
- p -> n_type = K_BREAK;
- p -> n_bcparent = brk_ref;
-
- need(SEMICOLON_TOK);
-
- RETURN_PTR("pn_break", p);
- }
-
- /*
- Parse the "case" statement.
- */
- static struct node *
- pn_case(void)
- {
- register struct node *p, *p1, *p2;
- register long con;
-
- /* Read the "case" */
-
- TICKB("pn_case");
-
- get_token();
-
- p1 = pe_expr();
- if (pe_number(p1)) {
- pe_retype(0, p1, K_CASE);
- }
- else {
- t_error("case constant is not constant");
- }
-
- /*
- SEE K&R p. 211; the expression will be folded to an INT
- primitive if and only if it is proper. Expressions using
- unary & are not proper--and in almost all cases will not
- fold.
- */
-
- /* Make sure we are in a switch body */
- if (sw_ref == NULL) {
- t_error("case appears outside of any switch");
- need(COLON_TOK);
- RETURN_PTR("pn_case", NULL);
- }
-
- /* Allocate a new case node. */
- p = new_pnode(sizeof(struct case_node));
- p -> n_type = K_CASE;
- p -> n_ccon = con = p1 -> n_const;
-
- /* Check the case list for duplicate entries -- and find its end */
- if (p1 = sw_ref -> n_slist) {
- do {
- TRACEP("pn_case",
- printf("check %p for duplicate\n", p1));
- if (p1 -> n_ccon == con) {
- t_3serr(p1, "duplicate case","","");
- break;
- }
- p2 = p1;
- }
- while (p1 = p1 -> n_clist);
-
- p2 -> n_clist = p;
- }
- else {
- sw_ref -> n_slist = p;
- }
- need(COLON_TOK);
-
- RETURN_PTR("pn_case", p);
- }
-
- /*
- Parse the "continue" statement.
- */
- static struct node *
- pn_continue(void)
- {
- register struct node * p;
-
- /* Read the "continue" */
-
- TICKB("pn_continue");
-
- get_token();
-
- /* Make sure the continue appears in a do, while or for. */
- if (cont_ref == NULL) {
- t_error("continue appears outside do, while and if");
- RETURN_PTR("pn_continue", NULL);
- }
-
- /* Allocate a break/continue node. */
- p = new_pnode(sizeof(struct bc_node));
- p -> n_type = K_CONTINUE;
- p -> n_bcparent = cont_ref;
-
- need(SEMICOLON_TOK);
-
- RETURN_PTR("pn_continue", p);
- }
-
- /*
- Parse the "default" statement.
- */
- static struct node *
- pn_default(void)
- {
- register struct node * p;
-
- /* Read the "default:" */
-
- TICKB("pn_default");
-
- get_token();
-
- /* Make sure we are in a switch statement. */
- if (sw_ref == NULL) {
- t_error("default appears outside of a switch");
- RETURN_PTR("pn_default", NULL);
- }
- if (sw_ref -> n_sdef) {
- t_error("duplicate default statement ignored");
- RETURN_PTR("pn_default", NULL);
- }
-
- /* Allocate a new case node. */
- p = new_pnode(sizeof(struct case_node));
- p -> n_type = K_DEFAULT;
-
- /* Link it as the default field of the parent switch. */
- sw_ref -> n_sdef = p;
-
- need(COLON_TOK);
-
- RETURN_PTR("pn_default", p);
- }
-
- /*
- L A B E L S, G O T O S A N D R E T U R N S.
- */
-
- /*
- Parse the "goto" statement.
- */
- static struct node *
- pn_goto(void)
- {
- register struct node * p;
- register struct lab_node *q;
-
- /* Read the "goto" */
-
- TICKB("pn_goto");
-
- get_token();
-
- /* Allocate a new plabel node. */
- if (t_type == ID_TOK) {
- p = new_pnode(sizeof(struct plabel_node));
- p -> n_type = K_GOTO;
-
- /*
- Get a pointer to the label node.
- Local symbols hide global symbols.
- */
- q = ll_lookup(t_symbol);
- if (q == NULL) {
- q = gl_lookup(t_symbol);
- if (q == NULL) {
- /*
- Allocate a referenced but not defined
- local label node. Thus, all GLOBAL labels
- must be defined before they are referenced.
- */
- q = ll_enter(t_symbol);
- }
- }
- p -> n_plab = q -> lab_label;
- }
- else {
- need(ID_TOK);
- }
-
- /* Read the symbol */
- get_token();
-
- (void) needend(SEMICOLON_TOK);
-
- RETURN_PTR("pn_goto", p);
- }
-
- /*
- Parse a user defined label.
- */
- static struct node *
- pn_label(void)
- {
- register struct node *p;
- register struct lab_node *q;
-
- TICKB("pn_label");
- TRACEP("pn_label", printf("(t_symbol: %s)\n", t_symbol));
-
- /* Allocate a new parse label node. */
- p = new_pnode(sizeof(struct plabel_node));
- p -> n_type = LABEL_TOK;
-
- /* The label should not exist. */
- if (scope.s_scope == FILE_SCOPE) {
- q = gl_lookup(t_symbol);
- }
- else {
- q = ll_lookup(t_symbol);
- }
- if (q != NULL && q -> lab_defined == TRUE) {
- t_2error("duplicate label definition for: ", t_symbol);
- p -> n_plab = 0L;
- }
- else if (q != NULL) {
- q -> lab_defined = TRUE;
- p -> n_plab = q -> lab_label;
- }
- else {
- /* Allocate a new label node. */
- q = ll_enter(t_symbol);
- q -> lab_defined = TRUE;
- p -> n_plab = q -> lab_label;
- }
-
- /* Skip over the label. */
- get_token();
-
- need(COLON_TOK);
-
- RETURN_PTR("pn_label", p);
- }
-
- /*
- Parse the "return" statement.
- */
- static struct node *
- pn_return(void)
- {
- register struct node * p;
- register struct type_node *t;
-
- /* Read the "return" */
-
- TICKB("pn_return");
-
- get_token();
-
- /* Allocate data structures */
- p = new_pnode(sizeof(struct ret_node));
- p -> n_type = K_RETURN;
-
- /* Access the return type */
- t = scope.s_fntype -> t_link;
-
- /* Parse an optional expression */
- if (t_type != SEMICOLON_TOK) {
- p -> n_rval = pe_expr();
- (void) pe_check(p -> n_rval, ANY_EXPR);
- }
-
- /* Check the expression */
- if (p -> n_rval == NULL) {
- if (t -> t_typtok != VOID_TYPE) {
- t_error("no return-value for function which has one");
- }
- }
- else {
- TRACE("pn_return",
- printf("pn_return: enclosing function:\n");
- pr_type(t);
- printf("return data:\n");
- pr_type(p -> n_rval -> n_cltype));
-
- if (pe_number(p -> n_rval)) {
- pe_massage(t, p -> n_rval, ASSN_TOK);
- }
- if (!pd_teq(t, p -> n_rval -> n_cltype)) {
- if (t -> t_typtok == VOID_TYPE) {
- t_error("return-value for void function");
- }
- else {
- t_error("type mismatch: returned type");
- }
- }
- }
- need(SEMICOLON_TOK);
-
- RETURN_PTR("pn_return", p);
- }
-
- /*
- E X T E N S I O N S.
- */
-
- /*
- Parse all machine language instructions.
- This IS different from pn_z.
- */
- static struct node *
- pn_x(void)
- {
- register int subtype;
- register struct node * p;
-
- TRACEPB("pn_x", printf("(t_subtype: %d)\n", t_subtype));
-
- /* Remember the subtype. */
- subtype = t_subtype;
-
- /* Parse the beginning of the pseudo function. */
- /* KLUDGE: character lookahead */
- skip_bl();
- if (ch != '(') {
- t_2warning(t_symbol, " is a pseudo function name");
- get_token();
- need(LPAREN_TOK); /* do nothing in some sense */
- if (t_type == COLON_TOK) {
- get_token();
- }
- RETURN_PTR("pn_x", NULL);
- }
- get_token(); /* put the paren up */
- get_token(); /* put the char after the paren up */
-
- /* Parse the inner expressions. */
- p = pn_x1(subtype);
-
- /* Parse the end of the pseudo function. */
- need(RPAREN_TOK);
- need(SEMICOLON_TOK);
-
- RETURN_PTR("pn_x", p);
- }
-
- /*
- CAUTION: by and large, allocation information is not available when
- this routine is executed. This implies that address-mode existence
- checks cannot be done at this time, but must be done by gen_x. Doing
- those checks later allows register names to be abstracted out, among
- other things.
- */
- static struct node *
- pn_x1(register int subtype)
- {
- register struct node * p;
- register struct node *p1;
- register struct lab_node *q;
-
- TRACEPB("pn_x1", printf("(%d)\n", subtype));
-
- switch (subtype) {
-
- case X_JMP:
- case X_JSR:
-
- TRACE("pn_x1", printf("pn_x1: JMP or JSR\n"));
-
- /* Allocate a new xtok_node. */
- p = new_pnode(sizeof(struct xtok_node));
- p -> n_type = X_TOK;
- p -> n_xtype = subtype;
-
- /* We may have either a label or an expression here. */
- if (t_type == ID_TOK && t_subtype == 0) {
- /* We assume it is a label. */
- p -> n_arg2 = pn_xlab();
- }
- else {
- /* Expression instead of label. */
- p -> n_xarg1 = pe_expr();
- }
- RETURN_PTR("pn_x1", p);
-
- case X_DBCC: case X_DBCS: case X_DBEQ:
- case X_DBF : case X_DBGE: case X_DBGT:
- case X_DBHI: case X_DBLE: case X_DBLS:
- case X_DBLT: case X_DBMI: case X_DBNE:
- case X_DBPL: case X_DBT: case X_DBVC:
- case X_DBVS:
-
- TRACE("pn_x1", printf("pn_x1: DBxx\n"));
-
- /* Allocate a new xtok_node. */
- p = new_pnode(sizeof(struct xtok_node));
- p -> n_type = X_TOK;
- p -> n_xtype = subtype;
-
- /* Get the first argument (not a label). */
- p -> n_xarg1 = pe_expr();
- need(COMMA_TOK);
- p -> n_arg2 = pn_xlab();
- RETURN_PTR("pn_x1", p);
-
- case X_BRA: case X_BSR:
- case X_BCC: case X_BCS: case X_BEQ:
- case X_BGE: case X_BGT: case X_BHI:
- case X_BLE: case X_BLS: case X_BLT:
- case X_BMI: case X_BNE: case X_BPL:
- case X_BVC: case X_BVS:
-
- TRACE("pn_x1", printf("pn_x1: BRA or Bxx\n"));
-
- /* Allocate a new xtok_node. */
- p = new_pnode(sizeof(struct xtok_node));
- p -> n_type = X_TOK;
- p -> n_xtype = subtype;
- p -> n_arg1 = pn_xlab();
- RETURN_PTR("pn_x1", p);
-
- default:
-
- TRACE("pn_x1", printf("pn_x1: default\n"));
-
- /* Allocate a new xtok_node. */
- p = new_pnode(sizeof(struct xtok_node));
- p -> n_type = X_TOK;
- p -> n_xtype = subtype;
-
- /* Instruction not involving a label. */
- p1 = pe_list(ARG_EXPR);
-
- /* Separate the zero, one or two arguments. */
- if (p1 && p1 -> n_type == SEPARATOR_TOK) {
- p -> n_xarg1 = p1 -> n_car;
- p1 = p1 -> n_next;
- if (p1 && p1 -> n_type == SEPARATOR_TOK) {
- t_error("too many arguments in pseudo function.");
- RETURN_PTR("pn_x1", NULL);
- }
- else {
- p -> n_xarg2 = p1;
- }
- }
- else if (p1) {
- p -> n_xarg1 = p1;
-
- }
- if (
- (p -> n_xarg1 && p -> n_xarg1 -> n_type != ID_TOK) ||
- (p -> n_xarg2 && p -> n_xarg2 -> n_type != ID_TOK)
- ) {
- t_error("pseudo function argument not a location");
- }
- RETURN_PTR("pn_x1", p);
- }
- }
-
- static struct node *
- pn_xlab(void)
- {
- register struct lab_node *p;
-
- TICKB("pn_xlab");
-
- if (t_type != ID_TOK || t_subtype != 0) {
- t_error("label expected");
- RETURN_PTR("pn_xlab", NULL);
- }
-
- /* Get a pointer to the label node. */
- if (scope.s_scope == FILE_SCOPE) {
- p = gl_lookup(t_symbol);
- if (p == NULL) {
- p = gl_enter(t_symbol);
- }
- }
- else {
- p = ll_lookup(t_symbol);
- if (p == NULL) {
- p = ll_enter(t_symbol);
- }
- }
-
- /* Skip over the symbol. */
- get_token();
-
- /* Return pointer to culabel_node. */
-
- RETURN_PTR("pn_xlab", p -> lab_label);
- }
-
- /*
- Parse all pseudo operations.
- */
- static struct node *
- pn_z(void)
- {
- register struct node * p;
- register int subtype;
-
- TRACEPB("pn_z", printf("(t_subtype: %d)\n", t_subtype));
-
- /* Remember the subtype. */
- subtype = t_subtype;
-
- /* Parse the beginning of the pseudo op */
- /* KLUDGE: character lookahead */
- skip_bl();
- if (ch != '(') {
- t_2warning(t_symbol, " is a pseudo operation name");
- get_token();
- need(LPAREN_TOK);
- if (t_type == COLON_TOK) {
- get_token();
- }
- RETURN_PTR("pn_z", NULL);
- }
- get_token();
- get_token();
-
- /* Parse the inner expressions. */
- p = pn_z1(subtype);
-
- /* Parse the end of the pseudo function. */
- need(RPAREN_TOK);
- need(SEMICOLON_TOK);
-
- RETURN_PTR("pn_z", p);
- }
-
- static struct node *
- pn_z1(register int subtype)
- {
- register struct node *p;
-
- TRACEPB("pn_z1", printf("(%d)\n", subtype));
-
- if (subtype == Z_BASE) {
- /* Set the f_base global but create no node. */
- if (is_areg(subtype)) {
- f_base = subtype;
- }
- else {
- t_error("sp or a-register expected");
- f_base = 0;
- }
- RETURN_PTR("pn_z1", NULL);
- }
- else if (subtype == Z_NOBASE) {
- f_base = 0;
- RETURN_PTR("pn_z1", NULL);
- }
-
- /* All other pseudo operations generate a parse node. */
- p = new_pnode(sizeof(struct ztok_node));
- p -> n_type = Z_TOK;
- p -> n_ztype = subtype;
-
- switch(subtype) {
-
- case Z_BSS: case Z_DATA: case Z_TEXT:
-
- RETURN_PTR("pn_z1", p);
-
- case Z_ORG: case Z_PUSH: case Z_POP:
- case Z_ADDSP: case Z_ADJSP: case Z_SUBSP:
-
- p -> n_zarg1 = pe_expr();
- RETURN_PTR("pn_z1", p);
-
- case Z_DC: case Z_DCB: case Z_DCW: case Z_DCL:
- case Z_DS: case Z_DSB: case Z_DSW: case Z_DSL:
-
- p -> n_zarg1 = pe_list(CONST_EXPR);
- RETURN_PTR("pn_z1", p);
-
- default:
- fatal("pn_z: unknown pseudo type");
- }
-
- TICKX("pn_z1");
- }
-
- /*
- L A B E L S Y M B O L T A B L E R O U T I N E S.
- */
-
- /*
- Enter a symbol in the global label list and mark it undefined.
- */
- static struct lab_node *
- gl_enter(char * symbol)
- {
- register struct lab_node * p;
-
- /* Make a new entry entry in the global label list. */
-
- TRACEPB("gl_enter", printf("(%s)\n", symbol));
-
- p = CAST(struct lab_node *) ml_alloc(sizeof(struct lab_node));
- p -> lab_defined = FALSE;
- p -> lab_label = new_culabel(symbol);
-
- /* Link it to the head of the list. */
- p -> lab_next = gl_head.lab_next;
- gl_head.lab_next = p;
-
- RETURN_PTR("gl_enter", p);
- }
-
- /*
- Initialize the global label list table.
- This must be done only once per program.
- */
- static void
- gl_init(void)
- {
- TICK("gl_init");
-
- gl_head.lab_next = 0L;
- }
-
- /*
- Look up a symbol in the global label list.
- */
- static struct lab_node *
- gl_lookup(char * symbol)
- {
- register struct lab_node * p;
-
- TRACEPB("gl_lookup", printf("(%s)\n", symbol));
-
- for (p = gl_head.lab_next; p != NULL; p = p -> lab_next) {
- if (str_eq(symbol, p -> lab_label -> c_labsym)) {
- RETURN_PTR("gl_lookup", p);
- }
- }
- RETURN_PTR("gl_lookup", NULL);
- }
-
- /*
- Check the local label list table to see if any labels
- have been referenced but not defined.
- This should be done at the end of each function.
- */
- static void
- ll_check(void)
- {
- register struct lab_node * p;
-
- TICK("ll_check");
-
- for (p = ll_head.lab_next; p; p = p -> lab_next) {
- if (p -> lab_defined == FALSE) {
- t_2error("undefined label: ",
- p -> lab_label -> c_labsym);
- }
- }
- }
-
- /*
- Enter a symbol in the local label list and mark it undefined.
- */
- static struct lab_node *
- ll_enter(char * symbol)
- {
- register struct lab_node * p;
-
- /* Make a new entry entry in the local label list. */
-
- TRACEPB("ll_enter", printf("(%s)\n", symbol));
-
- p = CAST(struct lab_node *) ml_alloc(sizeof(struct lab_node));
- p -> lab_defined = FALSE;
- p -> lab_label = new_culabel(symbol);
-
- /* Link it to the head of the list. */
- p -> lab_next = ll_head.lab_next;
- ll_head.lab_next = p;
-
- RETURN_PTR("ll_enter", p);
- }
-
- /*
- Initialize the local label list table.
- This must be done at the beginning of every function.
- */
- static void
- ll_init(void)
- {
- TICK("ll_init");
-
- ll_head.lab_next = 0L;
- }
-
- /*
- Look up a symbol in the local label list.
- */
- static struct lab_node *
- ll_lookup(char * symbol)
- {
- register struct lab_node * p;
-
- TRACEPB("ll_lookup", printf("(%s)\n", symbol));
-
- for (p = ll_head.lab_next; p != NULL; p = p -> lab_next) {
- if (str_eq(symbol, p -> lab_label -> c_labsym)) {
- RETURN_PTR("ll_lookup", p);
- }
- }
- RETURN_PTR("ll_lookup", NULL);
- }
-